// FocusMachineModel.cpp
#include "FocusMachineModel.h"
#include <QEventLoop>
#include <QVariant>
#include <QTimer>
#include <QDebug>
#include <QElapsedTimer>
#include <QCoreApplication>

FocusMachineModel::FocusMachineModel(const QString &clientName)
    : m_clientName(clientName), m_reconnectAttempts(0) {
    modbusClient = new QModbusTcpClient(this);
    isBigEndian = false; // 默认使用小端模式
    m_connectionMonitorTimer = new QTimer(this);
    connect(m_connectionMonitorTimer, &QTimer::timeout, this, &FocusMachineModel::checkConnection);
    qDebug() << "Created FocusMachineModel instance:" << m_clientName;
}

FocusMachineModel::~FocusMachineModel()
{
    if(!modbusClient){
        delete modbusClient;
        modbusClient = nullptr;
    }

    if(!m_connectionMonitorTimer){
        delete m_connectionMonitorTimer;
        m_connectionMonitorTimer = nullptr;
    }
}

void FocusMachineModel::setupModbusClient(const QString &ip, int port) {
    modbusClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, QVariant(ip));
    modbusClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, QVariant(static_cast<quint16>(port)));
}

bool FocusMachineModel::connectToModbusServer() {
    if (!modbusClient) {
        return false;
    }

    if (modbusClient->state() == QModbusDevice::ConnectedState) {
        qDebug() << "已经连接到 Modbus 设备，断开当前连接";
        modbusClient->disconnectDevice();
    }

    // 设置连接参数
    modbusClient->setTimeout(1000);
    modbusClient->setNumberOfRetries(10);

    // 创建事件循环和定时器
    QEventLoop loop;
    QTimer timer;
    timer.setSingleShot(true);

    bool connected = false;

    // 连接 stateChanged 信号
    QMetaObject::Connection conn = QObject::connect(modbusClient, &QModbusClient::stateChanged,
        [&](QModbusDevice::State state) {
            if (state == QModbusDevice::ConnectedState) {
                connected = true;
                loop.quit();
            } else if (state == QModbusDevice::UnconnectedState) {
                connected = false;
                loop.quit();
            }
        });

    // 开始连接
    if (!modbusClient->connectDevice()) {
        qDebug() << "连接 Modbus 设备失败";
        QObject::disconnect(conn);
        return false;
    }

    // 设置超时
    timer.start(5000);  // 5秒超时
    QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);

    // 等待连接结果或超时
    loop.exec();

    // 断开信号连接
    QObject::disconnect(conn);

    if (connected) {
        qDebug() << "成功连接到 Modbus 设备";
        startConnectionMonitoring();
        return true;
    } else {
        if (timer.isActive()) {
            qDebug() << "连接 Modbus 设备失败";
        } else {
            qDebug() << "连接 Modbus 设备超时";
        }
        return false;
    }
}

void FocusMachineModel::disconnectFromModbusServer() {
    if (!modbusClient || modbusClient->state() == QModbusDevice::UnconnectedState) {
        qDebug() << "已经断开连接或 Modbus 客户端不存在";
        return;
    }

    stopConnectionMonitoring(); // 主动断开连接时停止监控

    // 创建事件循环和定时器
    QEventLoop loop;
    QTimer timer;
    timer.setSingleShot(true);

    bool disconnected = false;

    // 连接 stateChanged 信号
    QMetaObject::Connection conn = QObject::connect(modbusClient, &QModbusClient::stateChanged,
        [&](QModbusDevice::State state) {
            if (state == QModbusDevice::UnconnectedState) {
                disconnected = true;
                loop.quit();
            }
        });

    // 开始断开连接
    modbusClient->disconnectDevice();

    // 设置超时
    timer.start(5000);  // 5秒超时
    QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);

    // 等待断开连接结果或超时
    loop.exec();

    // 断开信号连接
    QObject::disconnect(conn);

    if (disconnected) {
        qDebug() << "成功断开 Modbus 设备连接";
    } else {
        if (timer.isActive()) {
            qDebug() << "断开 Modbus 设备连接失败";
        } else {
            qDebug() << "断开 Modbus 设备连接超时";
        }
    }
}

void FocusMachineModel::startConnectionMonitoring() {
    m_connectionMonitorTimer->start(RECONNECT_INTERVAL);
}

void FocusMachineModel::stopConnectionMonitoring() {
    m_connectionMonitorTimer->stop();
}

void FocusMachineModel::checkConnection() {
    if (!isConnected()) {
        qDebug() << "Connection lost. Attempting to reconnect...";
        attemptReconnect();
    } else {
        m_reconnectAttempts = 0; // 重置重连尝试次数
    }
}

void FocusMachineModel::attemptReconnect() {
    if (m_reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
        m_reconnectAttempts++;
        qDebug() << "Reconnect attempt" << m_reconnectAttempts << "of" << MAX_RECONNECT_ATTEMPTS;
        
        if (reconnect(1, 0)) { // 尝试立即重连一次
            qDebug() << "Reconnection successful";
            m_reconnectAttempts = 0;
        } else {
            qDebug() << "Reconnection failed. Will try again in" << RECONNECT_INTERVAL / 1000 << "seconds";
        }
    } else {
        qDebug() << "Max reconnection attempts reached. Stopping connection monitoring.";
        stopConnectionMonitoring();
        emit reconnectFailed();
    }
}

//延时
void FocusMachineModel::MySleep(uint32_t ms)
{
    QElapsedTimer t;
    t.start();
    while(t.elapsed() < ms)
    {
        QCoreApplication::processEvents();
    }
}

//延时
bool FocusMachineModel::MySleep(uint32_t ms,bool *value)
{
    QElapsedTimer t;
    t.start();
    while(t.elapsed() < ms)
    {
        QCoreApplication::processEvents();

        if(*value == true)
        {
            return true;
        }
    }

    return false;
}


bool FocusMachineModel::readModbusFloat(int address, float &value, int timeout) {

    QEventLoop eventLoop;
    QTimer timer;
    timer.setSingleShot(true);
    bool success = false;


    auto *reply = modbusClient->sendReadRequest(QModbusDataUnit(QModbusDataUnit::HoldingRegisters, address, 2), 1);

    if (!reply) {
        setError("无法创建 Modbus 请求");
        return false;
    }

    QObject::connect(reply, &QModbusReply::finished, &eventLoop, &QEventLoop::quit);
    QObject::connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);

    timer.start(timeout);
    eventLoop.exec();

    if (timer.isActive()) {
        timer.stop();
        if (reply->error() == QModbusDevice::NoError) {
            uint16_t first = reply->result().value(0);
            uint16_t second = reply->result().value(1);
            value = convertToFloat(first, second);
            success = true;
        }
    } else {
        // 超时情况
        setError("读取浮点数失败");
        success = handleCommunicationError();
    }

    reply->deleteLater();

    if (!success) {
        setError("读取浮点数失败");
        return handleCommunicationError();
    }

    qDebug()<<"address"<<address<<"value"<<value<<"success"<<success;
    return success;
}

bool FocusMachineModel::writeModbusFloat(int address, float value, int timeout) {
    QEventLoop eventLoop;
    QTimer timer;
    timer.setSingleShot(true);
    bool success = false;

    uint16_t first, second;
    convertFloatToUint16(value, first, second);

    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, address, 2);
    writeUnit.setValue(0, first);
    writeUnit.setValue(1, second);

    auto *reply = modbusClient->sendWriteRequest(writeUnit, 1);
    if (reply) {
        QObject::connect(reply, &QModbusReply::finished, &eventLoop, &QEventLoop::quit);
        QObject::connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);

        timer.start(timeout);
        eventLoop.exec();

        if (timer.isActive()) {
            timer.stop();
            if (reply->error() == QModbusDevice::NoError) {
                success = true;
            }
        } else {
            // 超时情况
            setError("写入浮点数失败");
            success = handleCommunicationError();
        }

        reply->deleteLater();
    }

    return success;
}

bool FocusMachineModel::readModbusRegister(int address, int16_t &value, int timeout) {
    QEventLoop eventLoop;
    QTimer timer;
    timer.setSingleShot(true);
    bool success = false;

    auto *reply = modbusClient->sendReadRequest(QModbusDataUnit(QModbusDataUnit::HoldingRegisters, address, 1), 1);

    if (reply) {
        QObject::connect(reply, &QModbusReply::finished, &eventLoop, &QEventLoop::quit);
        QObject::connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);

        timer.start(timeout);
        eventLoop.exec();

        if (timer.isActive()) {
            timer.stop();
            if (reply->error() == QModbusDevice::NoError) {
                value = static_cast<int16_t>(reply->result().value(0));
                success = true;
            }
        } else {
            // 超时情况
            setError("读取寄存器失败");
            success = handleCommunicationError();
        }

        reply->deleteLater();
    }

    return success;
}

bool FocusMachineModel::writeModbusRegister(int address, int16_t value, int timeout) {
    QEventLoop eventLoop;
    QTimer timer;
    timer.setSingleShot(true);
    bool success = false;

    QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, address, 1);
    writeUnit.setValue(0, static_cast<quint16>(value));

    auto *reply = modbusClient->sendWriteRequest(writeUnit, 1);
    if (reply) {
        QObject::connect(reply, &QModbusReply::finished, &eventLoop, &QEventLoop::quit);
        QObject::connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);

        timer.start(timeout);
        eventLoop.exec();

        if (timer.isActive()) {
            timer.stop();
            if (reply->error() == QModbusDevice::NoError) {
                success = true;
            }
        } else {
            // 超时情况
            setError("写入寄存器失败");
            success = handleCommunicationError();
        }

        reply->deleteLater();
    }

    return success;
}

void FocusMachineModel::waitForRegisterValue(int address, int16_t expectedValue) {
    QEventLoop eventLoop;
    shouldCancelWait = false;

    auto checkValue = [this, address, expectedValue, &eventLoop]() {
        if (shouldCancelWait) {
            eventLoop.quit();
            return;
        }
        int16_t value;
        if (readModbusRegister(address, value)) {
            if (value == expectedValue) {
                emit registerValueChanged(address, value);
                eventLoop.quit();
            }
        }
    };

    QTimer pollTimer;
    connect(&pollTimer, &QTimer::timeout, this, checkValue);
    pollTimer.start(100); // 每100ms检查一次

    eventLoop.exec();

    pollTimer.stop();

    if (shouldCancelWait) {
        qDebug() << "Wait was cancelled";
    } else {
        qDebug() << "Register" << address << "changed to" << expectedValue;
    }
}

void FocusMachineModel::cancelWait() {
    shouldCancelWait = true;
}

bool FocusMachineModel::readCurrentCoordinates(int address, float &x, float &y, float &z, int timeout) {
    if (!modbusClient)
        return false;

    QModbusDataUnit readUnit(QModbusDataUnit::RegisterType::HoldingRegisters, address, 6);
    
    if (auto *reply = modbusClient->sendReadRequest(readUnit, 1)) {
        // 使用事件循环和定时器来等待回复
        QEventLoop loop;
        QTimer timer;
        timer.setSingleShot(true);
        
        QObject::connect(reply, &QModbusReply::finished, &loop, &QEventLoop::quit);
        QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
        
        timer.start(timeout);
        loop.exec();
        
        if (!timer.isActive()) {
            setError("读取坐标超时");
            return handleCommunicationError();
        }

        if (reply->error() != QModbusDevice::NoError) {
            setError("读取坐标失败: " + reply->errorString());
            return handleCommunicationError();
        }

        const QModbusDataUnit unit = reply->result();
        if (unit.valueCount() >= 6) {
            x = convertToFloat(unit.value(0), unit.value(1));
            y = convertToFloat(unit.value(2), unit.value(3));
            z = convertToFloat(unit.value(4), unit.value(5));
            reply->deleteLater();

            return true;
        }
    }

    return false;
}

float FocusMachineModel::convertToFloat(uint16_t first, uint16_t second) {
    uint32_t combined;
    if (isBigEndian) {
        combined = ((uint32_t)first << 16) | second;
    } else {
        combined = ((uint32_t)second << 16) | first;
    }
    float result;
    memcpy(&result, &combined, sizeof(result));
    return result;
}

bool FocusMachineModel::writeTargetMoveValue(int address, float x, float y, float z, int timeout) {
    if (!isConnected())
        return false;

    QModbusDataUnit writeUnit(QModbusDataUnit::RegisterType::HoldingRegisters, address, 6);
    
    uint16_t xFirst, xSecond, yFirst, ySecond, zFirst, zSecond;
    convertFloatToUint16(x, xFirst, xSecond);
    convertFloatToUint16(y, yFirst, ySecond);
    convertFloatToUint16(z, zFirst, zSecond);

    writeUnit.setValue(0, xFirst);
    writeUnit.setValue(1, xSecond);
    writeUnit.setValue(2, yFirst);
    writeUnit.setValue(3, ySecond);
    writeUnit.setValue(4, zFirst);
    writeUnit.setValue(5, zSecond);

    if (auto *reply = modbusClient->sendWriteRequest(writeUnit, 1)) {
        QEventLoop loop;
        QTimer timer;
        timer.setSingleShot(true);
        
        QObject::connect(reply, &QModbusReply::finished, &loop, &QEventLoop::quit);
        QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
        
        timer.start(timeout);
        loop.exec();
        
        if (timer.isActive()) {
            timer.stop();
            if (reply->error() == QModbusDevice::NoError) {
                reply->deleteLater();
                return true;
            }
        } else {
            setError("写入目标移动值失败");
            return handleCommunicationError();
        }
        
        reply->deleteLater();
    }

    return false;
}

void FocusMachineModel::convertFloatToUint16(float value, uint16_t &first, uint16_t &second) {
    uint32_t temp;
    memcpy(&temp, &value, sizeof(float));
    if (isBigEndian) {
        first = (temp >> 16) & 0xFFFF;
        second = temp & 0xFFFF;
    } else {
        second = (temp >> 16) & 0xFFFF;
        first = temp & 0xFFFF;
    }
}

void FocusMachineModel::setEndianness(bool bigEndian) {
    isBigEndian = bigEndian;
}

bool FocusMachineModel::isConnected() const {
    return modbusClient && modbusClient->state() == QModbusDevice::ConnectedState;
}

QString FocusMachineModel::getLastError() const {
    return m_lastError;
}

void FocusMachineModel::clearError() {
    m_lastError.clear();
    m_errorCount = 0;
}

bool FocusMachineModel::hasError() const {
    return !m_lastError.isEmpty();
}

void FocusMachineModel::setError(const QString &error) {
    m_lastError = error;
    m_errorCount++;
    emit errorOccurred(error);
    qDebug() << "Error occurred:" << error;
}

bool FocusMachineModel::handleCommunicationError() {
    if (m_errorCount >= MAX_ERRORS) {
        setError("通信错误次数过多，尝试重新连接");
        return reconnect();
    }
    return false;
}

bool FocusMachineModel::reconnect(int retries, int delay) {
    for (int i = 0; i < retries; ++i) {
        emit reconnectAttempt(i + 1, retries);
        disconnectFromModbusServer();
        MySleep(delay);
        if (connectToModbusServer()) {
            clearError();
            emit reconnectSucceeded();
            return true;
        }
    }
    setError("重新连接失败");
    emit reconnectFailed();
    return false;
}


